#include <arpa/inet.h>
#include <cerrno>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 12345

// 从fd上完整地读count字节到buf,直到读满或者出错
static ssize_t read_full(int fd, void *buf, size_t count) {
  size_t off = 0;
  ssize_t n;
  while (off < count) {
    n = read(fd, (char *)buf + off, count - off);
    if (n < 0) {
      if (errno == EINTR) {
        continue;
      }
    }
    if (n == 0) {
      // 对端关闭
      return off;
    }
    off += n;
  }
  return off;
}
int main(int argc, char *argv[]) {
  int sock;
  struct sockaddr_in srv_addr;

  // 1. 创建socket
  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    perror("socket");
    exit(EXIT_FAILURE);
  }
  // 2. 连接服务器
  memset(&srv_addr, 0, sizeof(srv_addr));
  srv_addr.sin_family = AF_INET;
  srv_addr.sin_port = htons(SERVER_PORT);
  if (inet_pton(AF_INET, SERVER_IP, &srv_addr.sin_addr) <= 0) {
    perror("inet_pton");
    close(sock);
    exit(EXIT_FAILURE);
  }
  if (connect(sock, (struct sockaddr *)&srv_addr, sizeof(srv_addr)) < 0) {
    perror("connect");
    close(sock);
    exit(EXIT_FAILURE);
  }
  printf("Connected to %s:%d\n", SERVER_IP, SERVER_PORT);
  while (1) {
    char *line = NULL;
    size_t len = 0;
    printf("> ");
    fflush(stdout);

    // getline 会分配或者扩展 buffer
    if (getline(&line, &len, stdin) < 0) {
      // EOF 或出错
      break;
    }
    // 去掉末尾换行
    size_t body_len = strcspn(line, "\r\n");
    line[body_len] = '\0';
    // 4字节+payload
    uint16_t msg_type = 1; // 你可以根据协议修改
    uint16_t net_type = htons(msg_type);
    uint16_t net_len = htons(body_len);
    size_t total = sizeof(net_type) + sizeof(net_len) + body_len;
    uint8_t *buf = static_cast<uint8_t *>(malloc(total));
    if (!buf) {
      perror("malloc");
      free(line);
      break;
    }
    memcpy(buf + 0, &net_type, sizeof(net_type));
    memcpy(buf + 2, &net_len, sizeof(net_len));
    memcpy(buf + 4, line, body_len);
    // 4. 发送
    if (write(sock, buf, total) != total) {
      perror("write");
      free(buf);
      free(line);
      break;
    }
    free(buf);
    // 5. 接收回复头
    uint16_t resp_type, resp_len;
    if (read_full(sock, &resp_type, sizeof(resp_type)) != sizeof(resp_type) ||
        read_full(sock, &resp_len, sizeof(resp_len)) != sizeof(resp_len)) {
      fprintf(stderr, "connection closed or read error\n");
      free(line);
      break;
    }
    resp_type = ntohs(resp_type);

    resp_len = ntohs(resp_len);
    // 6. 接收回复body
    uint8_t *body = static_cast<uint8_t *>(malloc(resp_len + 1));
    if (!body) {
      perror("malloc body");
      free(line);
      break;
    }
    if (read_full(sock, body, resp_len) != resp_len) {
      fprintf(stderr, "failed to read full body\n");
      free(body);
      free(line);
      break;
    }
    body[resp_len] = '\0'; // 方便当成字符串
    // 7. 显示
    printf("<< type=%u, len=%u, data=\"%s\"\n", resp_type, resp_len,
           (char *)body);

    free(body);
    free(line);
  }
  printf("Closing connection.\n");
  close(sock);
  return 0;
}
